import { createApp, h } from 'vue';
import { marked } from "marked";

// 是否为生产环境
const isProduction = process.env.NODE_ENV === 'production';
const publicPath = isProduction ? '' : '/public/';

const operator = {
  GET: async (path, option = {}) => {
    try {
      const res = await fetch(path, option)
      const data = await res.text()
      return data;
    } catch (err) {
      console.error('fetch错误！', err);
      throw err
    }
  }
}

// 计算缓入
function ease(a = 0, b = 100, len = 100, reverse = false) {
  const target = b;
  b += 1
  let c = new Array(len).fill(0)
  c.forEach((e, i) => {
    c[i] = a + b / 10
    b -= c[i]
  })

  let sum = c.reduce((accumulator, currentValue) => {
    return accumulator + currentValue
  })
  if (sum) {
    c.push(target - sum)
  }
  if (reverse) {
    c = c.map((e, i) => {
      return c[c.length - i - 1]
    })
  }
  return c
}

function linearGradient_transition(elem, from = "#fff", to = "#000", dir = 'to right', len = 100, time_interval = 0) {
  let current = 0,
    step = 0

  return new Promise(resolve => {
    const interval_arr = ease(0, 100, len)
    clearInterval(elem.timer)
    elem.timer = setInterval(() => {
      current = parseFloat(current) + interval_arr[step]
      step++
      $(elem).css({
        backgroundImage: `linear-gradient(${dir}, ${to}, ${current}%, ${from})`
      })
      if (step >= 101) {
        clearInterval(elem.timer)
        resolve()
      }
    }, time_interval)
  })
}


function loadStyle(path, link_class = 'hl_theme', link_data = 'data-v-2233') {
  const old = $('.' + link_class + link_data)
  // console.log(old);
  if (old.length) {
    old.attr('href', path)
  } else {
    const link = $(`<link rel="stylesheet" class="${link_class}" ${link_data} href="${path}">`)
    $(document.head).append(link)
  }
}

function loadScript(src, callback, async = false, className = 'script_node') {
  let script = document.querySelector(className)
  if (!script) {
    script = document.createElement('script')
    document.head.appendChild(script)
    script.className = className
    script.src = src
    script.async = async
    script.onload = () => callback()
  } else callback()
}

async function getModuleSync(mp) {
  return await import(mp).default
}

function msg(obj) {
  const init = {
    text: '',
    title: '提示',
    delay: 2000,
    allowClick: false,
    zt: null
  }

  if (typeof obj == 'string' || typeof obj == 'number') {
    init.text = obj.toString()
  } else {
    for (let k in obj) {
      init[k] = obj[k]
    }
  }

  init.text = init.text.toString()

  let msg_wrap = $('.msg_wrap')

  if (!msg_wrap.length) {
    msg_wrap = $(`<div class="msg_wrap markdown-body" style="margin-left: 0.4rem;margin-bottom: 0.3rem;height: unset;padding: unset;background: unset;overflow: unset;box-shadow: unset;">`)
    $(document.body).append(msg_wrap)
  }


  const md = $(marked.parse(init.text))
  md.find('*').each((i, e) => {
    if (e.innerHTML == '') {
      e.remove()
    }
  })

  const is_first = msg_wrap.find('*').length == 0
  const msg_content = $(`<div class="msg_content">`)
  const title_elem = $(`<h4>${init.title}</h4>`)
  const msg_elem = $(`<p>${md.html()}</p>`)

  msg_content.append(title_elem)
  msg_content.append(msg_elem)
  msg_wrap.append(msg_content)

  const mc_w = msg_content.outerWidth()
  const mc_h = msg_content.outerHeight()

  let msg_w = ''
  {
    // 手动设置大小
    const clone_wrap = $(msg_wrap[0].cloneNode()).html('')
    const clone_contnet = $(msg_content[0].cloneNode(true))

    clone_wrap.append(clone_contnet)
    $(document.body).append(clone_wrap)

    msg_w = clone_contnet.outerWidth()
    clone_wrap.remove()
  }

  msg_content.css({
    marginLeft: -mc_w + 'px',
    marginBottom: is_first ? 0 : -mc_h + 'px',
    pointerEvents: init.allowClick ? 'auto' : 'none',
    width: msg_w / parseFloat(document.documentElement.style.fontSize) + 'rem'
  }).animate({
    marginLeft: '0.4rem',
    marginBottom: '0.3rem'
  }, () => msg_content.delay(init.delay).animate({
    marginLeft: -mc_w + 'px',
    opacity: 0
  }, () => msg_content.delay(500).remove()))

  return new Promise(resolve => setTimeout(() => resolve(), init.zt ?? init.delay))
}

function decodeEntities(encodedString) {
  const textArea = document.createElement('textarea')
  textArea.innerHTML = encodedString
  return textArea.value
}


function get_vc_val(component, param) {
  const temp = document.createElement('div')

  const app = createApp({
    render() {
      return h(component, param)
    }
  }).mount(temp)

  let last, same_step = 0, timer;
  return new Promise(resolve => {
    app.$nextTick(() => {
      timer = setInterval(() => {
        let node = app.$el
        if (last == same_step.outerHTML) {
          same_step++
          if (same_step >= 70) {
            clearInterval(timer)
            resolve(node.cloneNode(true))
          }
        } else {
          same_step = 0
        }
      }, 100)
    })
  })
}

function trigger_event(eventType, trigger_elem, detail) {
  const event = new CustomEvent(eventType, {
    detail: detail
  })

  trigger_elem.dispatchEvent(event)
}

function url_search(href) {
  try {
    return JSON.parse('{' + href.split('?')[1].split('&').map(e =>
      '"' + e.replace('=', '":"') + '"'
    ).join(',') + '}')
  }
  catch {
    return {}
  }
}

// 创建递归属性
function createNestedProperties(obj, arr, val, rewrite) {
  const prop = arr.shift()
  if (arr.length == 0) {
    obj[prop] = val
    return
  } else {
    if (!obj.hasOwnProperty(prop)) {
      obj[prop] = {}
    } else if (typeof obj[prop] == 'object' && !Array.isArray(obj[prop])) {

    } else if (rewrite) {
      obj[prop] = {}
    }
    createNestedProperties(obj[prop], arr, val, rewrite)
  }
}

// 递归删除对象属性
function deleteNestedProperties(obj, arr) {
  const prop = arr.shift()
  if (arr.length == 0) {
    delete obj[prop]
    return
  } else if (obj[prop]) {
    deleteNestedProperties(obj[prop], arr)
  }
}

// 读取嵌套属性
function readNestedProperties(obj, arr) {
  const prop = arr.shift()
  if (arr.length == 0) {
    return obj[prop]
  } else if (obj[prop]) {
    return readNestedProperties(obj[prop], arr)
  }
}

// 融合对象，obj2 覆盖 obj1
function mergeObjects(obj1, obj2) {
  for (let key in obj2) {
    if (obj2.hasOwnProperty(key)) {
      if (obj2[key] instanceof Object && obj1.hasOwnProperty(key) && obj1[key] instanceof Object) {
        obj1[key] = mergeObjects(obj1[key], obj2[key])
      } else {
        obj1[key] = obj2[key]
      }
    }
  }
  return obj1;
}

// 导出模块
export {
  operator,
  publicPath,
  linearGradient_transition,
  ease,
  loadStyle,
  loadScript,
  getModuleSync,
  msg,
  decodeEntities,
  get_vc_val,
  trigger_event,
  url_search,
  createNestedProperties,
  deleteNestedProperties,
  readNestedProperties,
  mergeObjects
}